package us.cirion.adventure.ui.mobile;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;

import us.cirion.adventure.engine.Game;

/**
 * Stores or retrieves game data. In addition to the game state data, these
 * functions will also take into account some meta-data about the game,
 * including the version of the engine, the name of the game, and so on. These
 * fields should help ensure proper handling of saved games across different
 * versions of the application.
 * 
 * @author Chris
 */
class SaveGameRecord
{

	public static final int SAVE_GAME_FORMAT = 0;
	public static final String LAST_SAVED_GAME_KEY = "lastSavedGame";

	// The following are used for building and parsing metadata about a
	// saved game, which supports features such as autoloading the last
	// saved game. It's designed to be flexible so we can easily add new
	// fields in the future.
	private static final String FIELD_SEPARATOR = "^";
	private static final String SAVE_SLOT_FIELD = FIELD_SEPARATOR + "s";
	private static final String SAVE_GAME_FIELD = FIELD_SEPARATOR + "g";

	public static byte[] getSaveGameData(Game game, String saveGameName,
			int version) throws IOException
	{
		ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
		DataOutputStream dataOut = new DataOutputStream(byteOut);

		dataOut.writeInt(SAVE_GAME_FORMAT);
		dataOut.writeInt(version);
		dataOut.writeUTF(saveGameName);
		game.writeObject(dataOut);

		dataOut.flush();

		return byteOut.toByteArray();
	}

	public static void loadSaveGameData(byte[] data, Game game)
			throws IOException, UnrecognizedSaveFormatException
	{
		ByteArrayInputStream byteIn = new ByteArrayInputStream(data);
		DataInputStream dataIn = new DataInputStream(byteIn);
		int saveGameFormat = dataIn.readInt();
		if (saveGameFormat == 0)
		{
			dataIn.readInt(); // Engine version - currently not checked.
			dataIn.readUTF(); // Save game name - not important when loading.
			game.readObject(dataIn);
		} else
		{
			throw new UnrecognizedSaveFormatException(saveGameFormat);
		}
	}

	public static String getSaveGameRecordInfo(String gameFileLocation,
			String saveGameName)
	{
		return SAVE_GAME_FIELD + gameFileLocation + SAVE_SLOT_FIELD
				+ saveGameName;
	}

	public static String getGameName(String saveGameRecordInfo)
	{
		return getFieldContents(saveGameRecordInfo, SAVE_GAME_FIELD);
	}

	public static String getSlotName(String saveGameRecordInfo)
	{
		return getFieldContents(saveGameRecordInfo, SAVE_SLOT_FIELD);
	}

	private static String getFieldContents(String saveGameRecordInfo,
			String fieldMarker)
	{
		int fieldStartIndex = saveGameRecordInfo.indexOf(fieldMarker)
				+ fieldMarker.length();
		if (fieldStartIndex >= 0)
		{
			int fieldEndIndex = saveGameRecordInfo.indexOf(FIELD_SEPARATOR,
					fieldStartIndex);
			if (fieldEndIndex == -1)
			{
				fieldEndIndex = saveGameRecordInfo.length();
			}
			return saveGameRecordInfo.substring(fieldStartIndex, fieldEndIndex);
		}
		return null;
	}

	public static class UnrecognizedSaveFormatException extends Exception
	{

		private int version;

		public UnrecognizedSaveFormatException(int version)
		{
			this.version = version;
		}

		public String getMessage()
		{
			return "Save was version " + version + ".  This game uses version "
					+ SAVE_GAME_FORMAT;
		}

	}
}
